--******************************************************************************
-- File: xilinx_ball.vhd
-- Author: Matthew Hosking
-- Created: 09/01/2009
-- Description: A high level file to show the connections necessary between
--				various components (both VHDL & Verilog) used for the VGA driver.
-- NOTE:		Implementation based upon BALL.VHD from Quartus UP2 Core
--								and Olin Engineering COLOR_BARS.v example
--******************************************************************************
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL; -- '-' support
library work;
use work.SVGA_DEFINES_vhdl.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

--******************************************************************************
-- Entity Declaration
--******************************************************************************
ENTITY xilinx_ball IS
	PORT(
		SIGNAL PB1, PB2				: IN std_logic;
		SIGNAL pixel_clock			: IN std_logic;
		SIGNAL reset					: IN std_logic;
		SIGNAL pixel_count0			: IN std_logic_vector(10 downto 0);
		SIGNAL line_count0			: IN std_logic_vector(9 downto 0);
		SIGNAL vga_red_data			: OUT std_logic_vector(7 downto 0);
		SIGNAL vga_green_data		: OUT std_logic_vector(7 downto 0);
		SIGNAL vga_blue_data			: OUT std_logic_vector(7 downto 0);
		SIGNAL keyboard_clk 						: IN std_logic;
		SIGNAL keyboard_data 					: IN std_logic;
		SIGNAL clock_100Mhz	 					: IN std_logic;
		SIGNAL led_l,led_r,led_u,led_d	: OUT std_logic;
		SIGNAL inp									: IN std_logic

		
		
	);
END xilinx_ball;

--******************************************************************************
-- Architecture behavior
--****************************************************************************** 
architecture behavior of xilinx_ball is
   
	-- Video Display Signals   
	SIGNAL Ball_on1									: std_logic;
	SIGNAL Ball_on2									: std_logic;
	
	SIGNAL Sizex1,Sizey1 							: std_logic_vector(10 DOWNTO 0);
	SIGNAL Sizex2,Sizey2 							: std_logic_vector(10 DOWNTO 0);	
	
	SIGNAL Ball_Y_pos1, Ball_X_pos1				: std_logic_vector(10 DOWNTO 0);
	SIGNAL Ball_Y_pos2, Ball_X_pos2				: std_logic_vector(10 DOWNTO 0);
	signal Ball_Y_motion1							:std_logic_vector(10 DOWNTO 0);
	SIGNAL r_pixel_count1							: std_logic_vector(10 DOWNTO 0);
	SIGNAL r_line_count1								: std_logic_vector(10 DOWNTO 0);
	SIGNAL r_pixel_count2							: std_logic_vector(10 DOWNTO 0);
	SIGNAL r_line_count2								: std_logic_vector(10 DOWNTO 0);
	
	
	
	SIGNAL Ball_on									: std_logic;
	
	SIGNAL Size 							: std_logic_vector(10 DOWNTO 0);
	
	
	SIGNAL Ball_Y_pos, Ball_X_pos				: std_logic_vector(10 DOWNTO 0);
	
	signal Ball_Y_motion								:std_logic_vector(10 DOWNTO 0);
	signal Ball_X_motion								:std_logic_vector(10 DOWNTO 0);
	SIGNAL r_pixel_count							: std_logic_vector(10 DOWNTO 0);
	SIGNAL r_line_count						: std_logic_vector(10 DOWNTO 0);
	
   
	
	
			signal out1                :std_logic_vector(7 downto 0);
	
COMPONENT keyboard IS
		PORT(	
			keyboard_clk, keyboard_data, clock_25Mhz , 
			reset, read1		: IN	STD_LOGIC;
			scan_code		: OUT	STD_LOGIC_VECTOR(7 DOWNTO 0);
			scan_ready		: OUT	STD_LOGIC
		);
	END COMPONENT;
	signal 		sReset:std_logic;
Signal      sRead:std_logic;
signal      sScan_code:std_logic_vector(7 downto 0);
signal      sScan_ready:std_logic;



type state is (s0,s1,s2);

signal sState:state:=s0;

type keypress is (up,dwn,np);

signal key:keypress:=np;

signal gdata:std_logic:='1';

signal level:integer:=1;

BEGIN

	--Ball_Y_pos1 <= CONV_STD_LOGIC_VECTOR(150,11);					
	Ball_X_pos1 <= CONV_STD_LOGIC_VECTOR(15,11);
	Sizex1 <= CONV_STD_LOGIC_VECTOR(8,11);
	Sizey1 <= CONV_STD_LOGIC_VECTOR(80,11);
	--seg b
	--Ball_Y_pos2 <= CONV_STD_LOGIC_VECTOR(150,11);					
	Ball_X_pos2 <= CONV_STD_LOGIC_VECTOR(630,11);
	Sizex2 <= CONV_STD_LOGIC_VECTOR(8,11);
	Sizey2 <= CONV_STD_LOGIC_VECTOR(80,11);

  Size <= CONV_STD_LOGIC_VECTOR(8,11);
	--Ball_Y_pos <= CONV_STD_LOGIC_VECTOR(240,11);

	-- Colors for pixel data on video signal
	vga_green_data 	<= (others=>'1') when (gdata='1') else (others=>'0');
	-- Turn off Green and Blue when displaying ball
	vga_red_data <= (others=>'0') when ((Ball_on1='1')OR(Ball_on2='1')OR(Ball_on='1')) else (others=>'1');
	vga_blue_data 	<= (others=>'0') when ((Ball_on1='1')OR(Ball_on2='1')OR(Ball_on='1')) else (others=>'1');
	
	
	
KB: keyboard
		PORT MAP(
			keyboard_clk 	=> keyboard_clk,
			keyboard_data	=> keyboard_data,
			clock_25Mhz		=> clock_100Mhz,
			reset				=> sReset,
			read1				=> sRead,
			scan_code		=> sScan_code,
			scan_ready		=> sScan_ready	);
	
	--keyboard process......

process(sScan_ready,clock_100mhz,sReset,sState)


begin
if(clock_100Mhz'event and clock_100mhz='1') then
sRead<=sScan_ready;

if(sScan_ready='1') then
 
 if(sReset='1') then
   sState<=s0;
	
else 
	case sState is
	--state zeor accepts E0
	when s0 =>
	led_l<='1';
	led_r<='1';
	led_u<='1';
	led_d<='1';
   key<=up;
	if(sScan_code="11100000") then
	sState<=s1;
	else
	sState<=s0;
	end if;
	
	when s1=>
	---checks if the the NXT code is F0 is F0 then its not a make code any more it has changed state
	if(sScan_code="11110000")then
	sState<=s2;--change state


	--key press UP ON
	elsif(sScan_code="01110101")then
	led_l<='0';
	led_r<='0';
	led_u<='1';
	led_d<='1';
	key<=dwn;
	Ball_Y_motion1 <= - CONV_STD_LOGIC_VECTOR(2,11); 
	sState<=s0;--going HOME
	--key press DOWN ON
	elsif(sScan_code="01110010")then
	led_l<='1';
	led_r<='1';
	led_u<='0';
	led_d<='0';
	key<=dwn;
	Ball_Y_motion1 <= CONV_STD_LOGIC_VECTOR(2,11);
	sState<=s0;
	end if;
	
	
---checks if the the NXT code is E0..cool i for a BREAK :-)
	when s2=>
	--key Press UP OFF
	if(sScan_code="01110101")then
	led_l<='1';
	led_r<='1';
	key<=up;
	sState<=s0;--going HOME

	--key press DOWN OFF
	elsif(sScan_code="01110010")then
	led_u<='1';
	led_d<='1';
	key<=up;
	sState<=s0;

	end if;
	
	End case;
	
		end if;
	end if;
	end if;
end process;

	
	--seg a

	
	
	
	

	
	--------------------------------------------------------
	-- Paints the seg1 on screen
	--------------------------------------------------------	
	RGB_Display1: Process (Ball_X_pos1, Ball_Y_pos1, r_pixel_count1, r_line_count1, Sizex1, Sizey1)
	BEGIN
		-- Set Ball_on ='1' to display ball
		IF (('0' & Ball_X_pos1) <= (r_pixel_count1 + Sizex1)) 
		-- compare positive numbers only
		AND ((Ball_X_pos1 + Sizex1) >= ('0' & r_pixel_count1)) 
		AND (('0' & Ball_Y_pos1) <= (r_line_count1 + Sizey1)) 
		AND ((Ball_Y_pos1 + Sizey1) >= ('0' & r_line_count1) ) THEN
			Ball_on1 <= '1';
		ELSE
			Ball_on1 <= '0';
		END IF;
	END process RGB_Display1;
	
	--------------------------------------------------------
	-- Paints the seg2 on screen
	--------------------------------------------------------	
	RGB_Display2: Process (Ball_X_pos2, Ball_Y_pos2, r_pixel_count2, r_line_count2, Sizex2, Sizey2)
	BEGIN
		-- Set Ball_on ='1' to display ball
		IF (('0' & Ball_X_pos2) <= (r_pixel_count2 + Sizex2)) 
		-- compare positive numbers only
		AND ((Ball_X_pos2 + Sizex2) >= ('0' & r_pixel_count2)) 
		AND (('0' & Ball_Y_pos2) <= (r_line_count2 + Sizey2)) 
		AND ((Ball_Y_pos2 + Sizey2) >= ('0' & r_line_count2) ) THEN
			Ball_on2 <= '1';
		ELSE
			Ball_on2 <= '0';
		END IF;
	END process RGB_Display2;
	

RGB_Display: Process (Ball_X_pos, Ball_Y_pos, r_pixel_count, r_line_count, Size)
	BEGIN
		-- Set Ball_on ='1' to display ball
		IF (('0' & Ball_X_pos) <= (r_pixel_count + Size)) 
		-- compare positive numbers only
		AND ((Ball_X_pos + Size) >= ('0' & r_pixel_count)) 
		AND (('0' & Ball_Y_pos) <= (r_line_count + Size)) 
		AND ((Ball_Y_pos + Size) >= ('0' & r_line_count) ) THEN
			Ball_on <= '1';
		ELSE
			Ball_on <= '0';
		END IF;
	END process RGB_Display;
	
Move_Ball: process (pixel_clock, reset, level)
	BEGIN
		IF (pixel_clock'event AND pixel_clock='1') THEN
			IF (reset='1') THEN
			ELSE
				IF ((CONV_INTEGER('0' & r_pixel_count)=0) 
				AND (CONV_INTEGER('0' & r_line_count)=480)) THEN
					-- Bounce off top or bottom of screen
					IF ('0' & Ball_X_pos) >= CONV_STD_LOGIC_VECTOR(630,11) - Size THEN
						Ball_X_motion <= - CONV_STD_LOGIC_VECTOR(level,11);
					ELSIF Ball_X_pos <= Size+15 THEN
						Ball_X_motion <= CONV_STD_LOGIC_VECTOR(level,11);
					END IF;
					
					
					
					-- Compute next ball Y position
					
					IF ('0' & Ball_Y_pos) >= CONV_STD_LOGIC_VECTOR(480,11) - Size THEN
						Ball_Y_motion <= - CONV_STD_LOGIC_VECTOR(level,11);
					ELSIF Ball_Y_pos <= Size THEN
						Ball_Y_motion <= CONV_STD_LOGIC_VECTOR(level,11);
					END IF;
					
					
					
					if(key=dwn)and(gdata='1')then
					
--					if(( (Ball_Y_pos1+Ball_Y_motion1)>= CONV_STD_LOGIC_VECTOR(380,11)) and ((Ball_Y_pos1 + Ball_Y_motion1) >= Size)) then
--					Ball_Y_pos1<=Ball_Y_pos1;
--					else
					Ball_Y_pos1 <= Ball_Y_pos1 + Ball_Y_motion1;
--					end if;
					end if;
					
					if(gdata='1') then
					Ball_X_pos <= Ball_X_pos + Ball_X_motion;
					Ball_Y_pos <= Ball_Y_pos + Ball_Y_motion;

				--	if((('0' & (Ball_Y_pos2+Ball_Y_motion))<= CONV_STD_LOGIC_VECTOR(480,11) -Size ) and ((Ball_Y_pos2 + Ball_Y_motion) >= Size)) then
					--Ball_Y_pos2 <= Ball_Y_pos2;
					--else 
					Ball_Y_pos2 <= Ball_Y_pos2 + Ball_Y_motion;
              -- end if;
					end if;
					
					
					IF( Ball_X_pos=Ball_X_pos1+15) then
					if( Ball_Y_pos>=(Ball_Y_pos1+80) or Ball_Y_pos<=(Ball_Y_pos1-80))then
							gdata<='0';
							
							end if;
							else
							level<=level+ 1;
							end if;
							
					if((gdata='0')and(inp='0')) then
					    Ball_X_pos<=CONV_STD_LOGIC_VECTOR(300,11);
						 Ball_Y_pos<=CONV_STD_LOGIC_VECTOR(200,11);
						 Ball_Y_pos2<=CONV_STD_LOGIC_VECTOR(200,11);
						 Ball_Y_pos1<=CONV_STD_LOGIC_VECTOR(200,11);
						 gdata<='1';
						 end if;
					    
					
				END IF; -- end of screen refresh
			END IF; --if/else reset
		END IF; -- pixel_clock'event
	END process Move_Ball;



Gameplay: process (pixel_clock, reset)
BEGIN

End Process;

--Move_Ball1: process (pixel_clock, reset)
--	BEGIN
--		IF (pixel_clock'event AND pixel_clock='1') THEN
--			IF (reset='1') THEN
--			ELSE
--			IF ((CONV_INTEGER('0' & r_pixel_count1)=0) 
--			AND (CONV_INTEGER('0' & r_line_count1)=480)) THEN
--					-- Bounce off top or bottom of screen
--				   if(key=dwn) then
--					Ball_Y_pos1 <= Ball_Y_pos1 + Ball_Y_motion1;
--					end if;
--				END IF; -- end of screen refresh
--			END IF; --if/else reset
--		END IF; -- pixel_clock'event
--	END process Move_Ball1;
----		
--	Move_Ball2: process (pixel_clock, reset)
--	BEGIN
--		IF (pixel_clock'event AND pixel_clock='1') THEN
--			IF (reset='1') THEN
--			ELSE
--			IF ((CONV_INTEGER('0' & r_pixel_count2)=0) 
--			AND (CONV_INTEGER('0' & r_line_count2)=480)) THEN
--					-- Bounce off top or bottom of screen
--					--IF ('0' & Ball_Y_pos) >= CONV_STD_LOGIC_VECTOR(480,11) - Size THEN
--					--	Ball_Y_motion1 <= - CONV_STD_LOGIC_VECTOR(1,11);
--						
--					--ELSIF Ball_Y_pos <= Size THEN
--					--	Ball_Y_motion1 <= CONV_STD_LOGIC_VECTOR(1,11);
--					--END IF;					
--					--Ball_Y_pos2 <= Ball_Y_pos2 + Ball_Y_motion;
--					
--				END IF; -- end of screen refresh
--			END IF; --if/else reset
--		END IF; -- pixel_clock'event
--	END process Move_Ball2;	
		
		
		
		
		
		
		
		
	
	
	-- Line Counter Register
	--
	--		**from COLOR_BARS.v: 
	--		compensate for the delay caused by displaying the previous line while
	-- 	calculating the current line by using a line counter that is one line
	-- 	ahead of the original line counter
--	--------------------------------------------------------
	line_cntr: process (pixel_clock)
	BEGIN
		IF (pixel_clock'event AND pixel_clock='1') THEN
			IF((CONV_INTEGER('0' & line_count0) = (V_TOTAL - 2)) 
			AND (CONV_INTEGER('0' & pixel_count0) = (H_TOTAL - 3))) THEN
				--last pixel in last line of frame, so reset line counter
				r_line_count1 <= (others => '0');
				r_line_count2 <= (others => '0');
				r_line_count <= (others => '0');
				
			ELSIF (CONV_INTEGER('0' & pixel_count0) = (H_TOTAL - 3)) THEN
				--last pixel but not last line, so increment line counter
				r_line_count1 <= r_line_count1 + 1;		
				r_line_count2 <= r_line_count2 + 1;		
				r_line_count <= r_line_count + 1;		
					
			END IF;
		END IF; --pixel_clock'event
	END process line_cntr;

	--------------------------------------------------------
--	 Pixel Counter Register
	
	--		**from COLOR_BARS.v: 
	--		compensate for putting the pixel_count generation and the code that
	--		checks it on the same clock edge
--	------------------------------------------------------
	pixel_cntr: process (pixel_clock)
	BEGIN
		IF (pixel_clock'event AND pixel_clock='1') THEN
			IF ((CONV_INTEGER('0' & pixel_count0) = (H_TOTAL - 3))) THEN
				--last pixel in last line of frame, so reset line counter
				r_pixel_count1 <= (others=>'0');
				r_pixel_count2 <= (others=>'0');
				r_pixel_count <= (others=>'0');
				
			ELSE
				--last pixel but not last line, so increment line counter
				r_pixel_count1 <= r_pixel_count1 + 1;
				r_pixel_count2 <= r_pixel_count2 + 1;
				r_pixel_count <= r_pixel_count + 1;
				
			END IF;
		END IF; --pixel_clock'event
	END process pixel_cntr;
	
	
	
	
END behavior;